<?php

require_once( "PhpFaces/Context/FacesContext.php" );
require_once( "PhpFaces/Component/UIComponent.php" );

/**
 * ViewHandler is the pluggablity mechanism for allowing 
 * implementations of or applications using the JavaServer 
 * Faces specification to provide their own handling of 
 * the activities in the Render Response and Restore View  
 * phases of the request processing lifecycle. This allows 
 * for implementations to support different response generation 
 * technologies, as well as alternative strategies for saving 
 * and restoring the state of each view.
 * 
 * Please see StateManager for information on how the ViewHandler 
 * interacts the StateManager. 
 */
class PhpFaces_ViewHandler_FaceletViewHandler {

	private $taglibs;

	public function __construct() {
		$this->taglibs = array();
		
		$taglib = new PhpFaces_Taglib( "phpfaces.taglib.xml" );
		$taglib->parse();
		
		$this->taglibs[] = $taglib;
	}

	/** Create and return a new UIViewRoot instance initialized with information from the argument FacesContext and viewId. */
	public function createView( PhpFaces_Context_FacesContext $facesContext, $viewId ) {
		$configXml = new XmlReader();
		$configXml->open( $this->path );
		$configXml->setParserProperty(2,true); // This seems a little unclear to me - but it worked :)

		$viewRoot = new PhpFaces_UI_UIViewRoot();
		$componentStack[] = array();
		
		$componentLevel = 0;
		$componentStack[$componentLevel] = $viewRoot;
		// init the verbatim buffer
		$verbatimBuffer = "";
		
		while( $configXml->read() ) {
		
			$currentComponent =& $componentStack[$componentLevel];

			$taglib = $this->getTablibForNamespace( $configXml->namespaceURI );
			if( $taglib != null ) {
				$tag = $taglib->lookupTag( $configXml->localName );
								
				if( $tag != null ) {

					// handle any empty content we've encountered at this level
					// by adding to to the current node as "verbatim" UIOutput
					if( $configXml->nodeType == XMLReader::ELEMENT || $configXml->nodeType == XMLReader::END_ELEMENT ) {

						$output = new PhpFaces_UI_UIOutput();
						$output->setParent( $currentComponent );
						$output->setValue( $verbatimBuffer );
						$children =& $currentComponent->getChildren();
						$children[] = $output;
						// reset the verbatim buffer since we got the content needed from it
						$verbatimBuffer = "";
					}
						
					if( $configXml->nodeType == XMLReader::ELEMENT ) {
						// lookup the component type
						$componentType = $tag->getComponentType();
						$componentEntries = $config->getComponentEntries();
						$componentClass = null;
						foreach( $componentEntries  as $componentEntry ) {
							if( $componentEntry->type == $componentType ) {
								$componentClass = $componentEntry->class;
							}
						}
						
						// create the component if we can
						$newComponent = null;
						if( class_exists( $componentClass ) 
							&& (($newComponent = new $componentClass) instanceof PhpFaces_UI_UIComponent) ) {
	
	
							// add the component to the tree
							$children =& $currentComponent->getChildren();
							$children[] = $currentComponent;
							$newComponent->setParent( $currentComponent );
	
							// set the component's attributes
							// TODO add the taghandler like facelets has
							if( $configXml->hasAttributes ) {
								while( $configXml->moveToNextAttribute() ) {
									$attributeName = $configXml->name;
									$value = $configXml->value;
	
									if( property_exists( $currentComponent, $attributeName ) ) {
										$currentComponent->$attributeName = $value;
									} elseif( method_exists( $currentComponent, ($setterName="set$attributeName") ) ) {
										call_user_func( array( $currentComponent, $setterName ), $value );
									}
								}
	
								$configXml->moveToElement();
							}
							
							// increment the component level and add this to the stack
							$componentLevel++;
							$componentStack[$componentLevel] = $newComponent;
							
						}
						
						
					} 

					// close the element by taking it off the stack and decrementing the current level
					if ( $configXml->nodeType == XMLReader::END_ELEMENT || $configXml->isEmptyElement ) {
						unset( $componentStack[$componentLevel] );
						$componentLevel--;
					} else {
						// tag exists, but the component is invalid (not a UIComponent subclass, or a class at all)
					}
			
				} else {
					// taglib exists, but no matching tag exists
				}
			} else { // if( $taglib != null ) {
				// no taglib
				
				// append stuff directly to the verbatim buffer that will be added at the beginning of a new component
				// or end of the current component
				$verbatimBuffer .= $configXml->name;
			}
			
		}// while
	} // function
	
	/**  Perform whatever actions are required to render the response view to the response object associated with the current FacesContext. */
	public function renderView( PhpFaces_Context_FacesContext $facesContext, /* PhpFaces_UIViewRoot */ $viewToRender ) {
		
	}
	
	
	
	
	protected function getTablibForNamespace( $namespace ) {
		foreach( $this->taglibs as $taglib ) {
			if( $taglib->getNamespace() == $namespace ) {
				return $taglib;
			}
		}
	}
}

?>